<!DOCTYPE HTML>
<html lang="zh-Hans" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>译：Copy-On-Write是不是优化？ - Rust 优秀博文</title>


        <!-- Custom HTML head -->
        
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="../../favicon.svg">
        <link rel="shortcut icon" href="../../favicon.png">
        <link rel="stylesheet" href="../../css/variables.css">
        <link rel="stylesheet" href="../../css/general.css">
        <link rel="stylesheet" href="../../css/chrome.css">
        <link rel="stylesheet" href="../../css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="../../fonts/fonts.css">

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="../../highlight.css">
        <link rel="stylesheet" href="../../tomorrow-night.css">
        <link rel="stylesheet" href="../../ayu-highlight.css">

        <!-- Custom theme stylesheets -->

    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "../../";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">1.</strong> 类型系统</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../01_类型系统/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow.html"><strong aria-hidden="true">1.1.</strong> Rust Concept Clarification Deref vs AsRef vs Borrow vs Cow</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow/Deref_AsRef_Borrow_Cow释义.html"><strong aria-hidden="true">1.2.</strong> Deref AsRef Borrow Cow 释义</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然/Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然.html"><strong aria-hidden="true">1.3.</strong> Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust的Cow类型有什么用？详解Cow及其用途/Rust的Cow类型有什么用？详解Cow及其用途.html"><strong aria-hidden="true">1.4.</strong> Rust的Cow类型有什么用？详解Cow及其用途</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/判别Fn、FnMut、FnOnce的标准/判别Fn、FnMut、FnOnce的标准.html"><strong aria-hidden="true">1.5.</strong> 判别Fn、FnMut、FnOnce的标准</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/一行代码告诉你内部可变性的真相(UnsafeCell)/一行代码告诉你内部可变性的真相(UnsafeCell).html"><strong aria-hidden="true">1.6.</strong> 一行代码告诉你内部可变性的真相(UnsafeCell)</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Tour_of_Rust's_Standard_Library_Traits/Tour_of_Rust's_Standard_Library_Traits.html"><strong aria-hidden="true">1.7.</strong> Tour of Rust's Standard Library Traits</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/逆变、协变与子类型，以及Rust/逆变、协变与子类型，以及Rust.html"><strong aria-hidden="true">1.8.</strong> 逆变、协变与子类型，以及Rust</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust自引用结构、Pin与Unpin/Rust自引用结构、Pin与Unpin.html"><strong aria-hidden="true">1.9.</strong> Rust自引用结构、Pin与Unpin</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/为什么Rust需要Pin,Unpin/为什么Rust需要Pin,Unpin.html"><strong aria-hidden="true">1.10.</strong> 译：为什么 Rust 需要 Pin, Unpin ？</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/定海神针Pin和Unpin/定海神针Pin和Unpin.html"><strong aria-hidden="true">1.11.</strong> 译：定海神针 Pin 和 Unpin</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/sizedness-in-rust/sizedness-in-rust.html"><strong aria-hidden="true">1.12.</strong> Sizedness in Rust</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust生命周期集大成者PhantomData〈T〉/Rust生命周期集大成者PhantomData〈T〉.html"><strong aria-hidden="true">1.13.</strong> Rust生命周期集大成者 PhantomData&lt;T&gt;</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用Rust做类型体操_Part_0.html"><strong aria-hidden="true">1.14.</strong> 数据库表达式执行的黑魔法：用Rust做类型体操 Part 0</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：GAT实现引用类型关联_Part_1.html"><strong aria-hidden="true">1.15.</strong> 数据库表达式执行的黑魔法：GAT实现引用类型关联 Part 1</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用HRTB写bound_Part_2.html"><strong aria-hidden="true">1.16.</strong> 数据库表达式执行的黑魔法：用HRTB写bound Part 2</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用Rust做类型体操之用宏展开重复代码_Part_3_&_4.html"><strong aria-hidden="true">1.17.</strong> 数据库表达式执行的黑魔法：用Rust做类型体操之用宏展开重复代码 Part 3 & 4</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：与Rust编译器斗智斗勇之表达式向量化_Part_5_&_6.html"><strong aria-hidden="true">1.18.</strong> 数据库表达式执行的黑魔法：与Rust编译器斗智斗勇之表达式向量化 Part 5 & 6</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：在Rust中用宏关联逻辑类型和实际类型_Part_7.html"><strong aria-hidden="true">1.19.</strong> 数据库表达式执行的黑魔法：在Rust中用宏关联逻辑类型和实际类型 Part 7</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">2.</strong> 生命周期</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../02_生命周期/Rust中的生命周期——从StrSplit实例说开去/Rust中的生命周期——从StrSplit实例说开去.html"><strong aria-hidden="true">2.1.</strong> Rust中的生命周期——从StrSplit实例说开去</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/与ChatGPT深度对话来学Rust生命周期/与ChatGPT深度对话来学Rust生命周期.html"><strong aria-hidden="true">2.2.</strong> 与ChatGPT深度对话来学Rust生命周期</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——early_bound与late_bound（1）/进击的Rust生命周期——early_bound与late_bound（1）.html"><strong aria-hidden="true">2.3.</strong> 进击的Rust生命周期——early_bound与late_bound（1）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——early_bound与late_bound（2）/进击的Rust生命周期——early_bound与late_bound（2）.html"><strong aria-hidden="true">2.4.</strong> 进击的Rust生命周期——early_bound与late_bound（2）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——一力降十会的MIR（1）/进击的Rust生命周期——一力降十会的MIR（1）.html"><strong aria-hidden="true">2.5.</strong> 进击的Rust生命周期——一力降十会的MIR（1）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——一力降十会的MIR（2）/进击的Rust生命周期——一力降十会的MIR（2）.html"><strong aria-hidden="true">2.6.</strong> 进击的Rust生命周期——一力降十会的MIR（2）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/Common_Rust_Lifetime_Misconceptions/Common_Rust_Lifetime_Misconceptions.html"><strong aria-hidden="true">2.7.</strong> Common Rust Lifetime Misconceptions</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/Rust生命周期常见误区/Rust生命周期常见误区.html"><strong aria-hidden="true">2.8.</strong> 译：Rust生命周期常见误区</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">3.</strong> 无畏并发</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../05_无畏并发/简单写个Rust无锁队列/简单写个Rust无锁队列.html"><strong aria-hidden="true">3.1.</strong> 简单写个Rust无锁队列</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——混合自旋锁/进击的Rust多线程——混合自旋锁.html"><strong aria-hidden="true">3.2.</strong> 进击的Rust多线程——混合自旋锁</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/An_unsafe_tour_of_Rust's_Send_and_Sync/An_unsafe_tour_of_Rust's_Send_and_Sync.html"><strong aria-hidden="true">3.3.</strong> An unsafe tour of Rust's Send and Sync</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——Send与Sync/进击的Rust多线程——Send与Sync.html"><strong aria-hidden="true">3.4.</strong> 进击的Rust多线程——Send与Sync</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——离经叛道的PhantomData/进击的Rust多线程——离经叛道的PhantomData.html"><strong aria-hidden="true">3.5.</strong> 进击的Rust多线程——离经叛道的PhantomData</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust_Async_Pin概念解析/Rust_Async_Pin概念解析.html"><strong aria-hidden="true">3.6.</strong> Rust Async: Pin概念解析</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust和C++的并发库对比/Rust和C++的并发库对比.html"><strong aria-hidden="true">3.7.</strong> 译：Rust 和 C++ 的并发库对比</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust原子类型和内存排序/Rust原子类型和内存排序.html"><strong aria-hidden="true">3.8.</strong> Rust原子类型和内存排序</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">4.</strong> 网络编程</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../06_网络编程/从编解码层面理解WebSocket_手写一个WebSocket/从编解码层面理解WebSocket_手写一个WebSocket.html"><strong aria-hidden="true">4.1.</strong> 从编解码层面理解WebSocket 手写一 个WebSocket</a></li><li class="chapter-item expanded "><a href="../../06_网络编程/透过Rust探索系统的本原：网络篇/透过Rust探索系统的本原：网络篇.html"><strong aria-hidden="true">4.2.</strong> 透过Rust探索系统的本原：网络篇</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">5.</strong> 轮子系列</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../07_轮子系列/700行Rust写一个内存分配器/700行Rust写一个内存分配器.html"><strong aria-hidden="true">5.1.</strong> 700行Rust写一个内存分配器</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/Rust：网络库的实现思路/Rust：网络库的实现思路.html"><strong aria-hidden="true">5.2.</strong> Rust：网络库的实现思路</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/Rust异步运行时基础部件/Rust异步运行时基础部件.html"><strong aria-hidden="true">5.3.</strong> Rust异步运行时基础部件</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（1）.html"><strong aria-hidden="true">5.4.</strong> 使用Rust+epoll编写异步IO框架（1）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（2）.html"><strong aria-hidden="true">5.5.</strong> 使用Rust+epoll编写异步IO框架（2）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（3）.html"><strong aria-hidden="true">5.6.</strong> 使用Rust+epoll编写异步IO框架（3）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day1.html"><strong aria-hidden="true">5.7.</strong> 用rust从零开发一套web框架：day1</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day2.html"><strong aria-hidden="true">5.8.</strong> 用rust从零开发一套web框架：day2</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day3.html"><strong aria-hidden="true">5.9.</strong> 用rust从零开发一套web框架：day3</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day4.html"><strong aria-hidden="true">5.10.</strong> 用rust从零开发一套web框架：day4</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day5.html"><strong aria-hidden="true">5.11.</strong> 用rust从零开发一套web框架：day5</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">6.</strong> 奇技淫巧</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Copy-On-Write是不是优化？/Copy-On-Write是不是优化？.html" class="active"><strong aria-hidden="true">6.1.</strong> 译：Copy-On-Write是不是优化？</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/揭秘神奇的Rust_Axum风格的函数实现/揭秘神奇的Rust_Axum风格的函数实现.html"><strong aria-hidden="true">6.2.</strong> 译：揭秘神奇的 Rust Axum 风格的函数实现</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/“变长参数”函数与回调/“变长参数”函数与回调.html"><strong aria-hidden="true">6.3.</strong> “变长参数”函数与回调</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Rust字符串格式化的幕后：format_args!()/Rust字符串格式化的幕后：format_args!().html"><strong aria-hidden="true">6.4.</strong> 译：Rust字符串格式化的幕后：format_args!()</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/给Rust带来一点C++特产/给Rust带来一点C++特产.html"><strong aria-hidden="true">6.5.</strong> 给Rust带来一点C++特产</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/一步步实现_Rust_Bevy_ECS_的_System_简化版本/一步步实现_Rust_Bevy_ECS_的_System_简化版本.html"><strong aria-hidden="true">6.6.</strong> 一步步实现 Rust Bevy ECS 的 System 简化版本</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Exploring_Design_Patterns_in_Rust_with_Algorithmic_Trading_Examples/Exploring_Design_Patterns_in_Rust_with_Algorithmic_Trading_Examples.html"><strong aria-hidden="true">6.7.</strong> Exploring Design Patterns in Rust with Algorithmic Trading Examples</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">7.</strong> 源码分析</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：bytes源码分析/Rust并发：bytes源码分析.html"><strong aria-hidden="true">7.1.</strong> Rust并发：bytes源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：标准库Arc源码分析/Rust并发：标准库Arc源码分析.html"><strong aria-hidden="true">7.2.</strong> Rust并发：标准库Arc源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：标准库sync_Once源码分析/Rust并发：标准库sync_Once源码分析.html"><strong aria-hidden="true">7.3.</strong> Rust并发：标准库sync::Once源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust源码阅读：引用计数Rc/Rust源码阅读：引用计数Rc.html"><strong aria-hidden="true">7.4.</strong> Rust源码阅读：引用计数Rc</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust源码阅读：Cell、RefCell与内部可变性/Rust源码阅读：Cell、RefCell与内部可变性.html"><strong aria-hidden="true">7.5.</strong> Rust源码阅读： Cell、RefCell与内部可变性</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/关于_Rust_的_UnsafeCell、Cell_与_RefCell/关于_Rust_的_UnsafeCell、Cell_与_RefCell.html"><strong aria-hidden="true">7.6.</strong> 关于 Rust 的 UnsafeCell、Cell 与 RefCell</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust_Async_async-stream源码分析/Rust_Async_async-stream源码分析.html"><strong aria-hidden="true">7.7.</strong> Rust Async: async-stream源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/走进Tokio的异步世界/走进Tokio的异步世界.html"><strong aria-hidden="true">7.8.</strong> 走进 Tokio 的异步世界</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/tokio.rs_runtime的实现/tokio.rs_runtime的实现.html"><strong aria-hidden="true">7.9.</strong> tokio.rs runtime 的实现</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_internals/Tokio_internals.html"><strong aria-hidden="true">7.10.</strong> Tokio internals</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_internals/译文：Tokio內部机制.html"><strong aria-hidden="true">7.11.</strong> 译：Tokio 内部机制</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust_Axum_HTTP_框架的架构分析/Rust_Axum_HTTP_框架的架构分析.html"><strong aria-hidden="true">7.12.</strong> Rust Axum HTTP 框架的架构分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/安利一个Rust_Game_Engine：Bevy--ECS部分/安利一个Rust_Game_Engine：Bevy--ECS部分.html"><strong aria-hidden="true">7.13.</strong> 安利一个Rust Game Engine：Bevy--ECS部分</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_解析之任务调度/Tokio_解析之任务调度.html"><strong aria-hidden="true">7.14.</strong> Tokio 解析之任务调度</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">8.</strong> 生态观察</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../11_生态观察/Rust_web_frameworks_have_subpar_error_reporting/Rust_web_frameworks_have_subpar_error_reporting.html"><strong aria-hidden="true">8.1.</strong> Rust web frameworks have subpar error reporting</a></li><li class="chapter-item expanded "><a href="../../11_生态观察/SeaORM：要做Rust版本的ActiveRecord/SeaORM：要做Rust版本的ActiveRecord.html"><strong aria-hidden="true">8.2.</strong> SeaORM：要做Rust版本的ActiveRecord</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">9.</strong> 死灵终极</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_总述.html"><strong aria-hidden="true">9.1.</strong> 译：Learn Rust the Dangerous Way 总述</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_0.html"><strong aria-hidden="true">9.2.</strong> 译：Learn Rust the Dangerous Way 0</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_1.html"><strong aria-hidden="true">9.3.</strong> 译：Learn Rust the Dangerous Way 1</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_2.html"><strong aria-hidden="true">9.4.</strong> 译：Learn Rust the Dangerous Way 2</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_3.html"><strong aria-hidden="true">9.5.</strong> 译：Learn Rust the Dangerous Way 3</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_4.html"><strong aria-hidden="true">9.6.</strong> 译：Learn Rust the Dangerous Way 4</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_5.html"><strong aria-hidden="true">9.7.</strong> 译：Learn Rust the Dangerous Way 5</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（一）.html"><strong aria-hidden="true">9.8.</strong> Unsafe Rust 随堂小测（一）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（二）.html"><strong aria-hidden="true">9.9.</strong> Unsafe Rust 随堂小测（二）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（三）.html"><strong aria-hidden="true">9.10.</strong> Unsafe Rust 随堂小测（三）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测参考答案.html"><strong aria-hidden="true">9.11.</strong> Unsafe Rust 随堂小测参考答案</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">Rust 优秀博文</h1>

                    <div class="right-buttons">
                        <a href="../../print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>

                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="译copy-on-write是不是优化"><a class="header" href="#译copy-on-write是不是优化">译：Copy-On-Write是不是优化？</a></h1>
<p>作者：oribenshir</p>
<p>原载：<a href="https://oribenshir.github.io/afternoon_rusting/blog/copy-on-write">https://oribenshir.github.io/afternoon_rusting/blog/copy-on-write</a></p>
<p>译者：<a href="https://www.zhihu.com/people/tony-folly">Praying</a></p>
<p>译稿：<a href="https://zhuanlan.zhihu.com/p/114589096">https://zhuanlan.zhihu.com/p/114589096</a></p>
<p>原文标题: Optimizations That Aren't, Or Are They?</p>
<p>几年前，我读到了一篇关于C++的很特别的博客。这是我第一次接触到技术博客的概念。它使我在教育体系(如陈旧的经典课程，练习，坐在教室里听老师讲课)之外接触到了完整的软件开发的概念。直到今天，那都是我最喜欢的博客之一，这也使我有了想要写出属于自己的博客的强烈愿望。</p>
<h2 id="the-concept-of-copy-on-write"><a class="header" href="#the-concept-of-copy-on-write">The concept of Copy-On-Write</a></h2>
<p>这篇博客是Herb Sutter在20多年前写的，你可以在<a href="https://link.zhihu.com/?target=http%3A//www.gotw.ca/publications/optimizations.htm">这里</a>看到。时隔20多年，在讨论这篇博客及为什么与它有关之前，我们需要讲一些背景。它讲述了一种叫做Copy-On-Write的优化，缩写为COW。我会分别在Rust和C++里讨论这个优化。但是也不要担心，我会详细地进行说明，不需要了解很多有关这些语言的背景知识。在我们开始之前，先介绍一下这个词的起源。在Rust里，COW实际上表示Clone-On-Write，这个优化用于处理较大的数据。在Rust里，我们对较大的数据进行克隆(clone)而不是拷贝(copy)。不过幸运的是，克隆(Clone)和拷贝(Copy)的单词开头都是相同的字母，所以只要简单地记为COW就可以了。但是在本文中，如果需要的话，我会一直悄悄变换克隆(clone)和拷贝(copy)的语义。其实我说的都是相同的操作，即把一大块数据从一个地方拷贝到另一个地方。</p>
<p>Copy-On-Write最关键的地方在于拷贝数据是一个成本相对较高的操作。我们想要尽可能地减少这种操作。让我们来考虑一下什么时候有必要拷贝一份数据。如果你对Rust的所有权系统比较熟悉(或许你应该熟悉)，可能就会觉得比较直观。当所有权系统会阻止你做一些事情，你需要拷贝数据或者找到其他的方法面对这个问题(这都是后话)。不管怎样，对于你们中对Rust的所有权系统不太熟悉的那些人，让我们展开讨论。只要我们有一个变量引用到一块数据，我们就不应该到处拷贝它。没人能在我们的封装下修改它，这正是我们所担心的场景。拷贝数据只有在多个变量指向同一块数据时才会相关联。但是这里正是COW背后的优化部分。不是每一次，我们都有很多变量指向相同的数据，实际上我们不得不去拷贝它。如果我们所做的只是从变量的位置读取数据，我们仍然没有理由把它到处拷贝。没有人改变它，所以我们没有面对数据竞争。数据竞争是这样一种情况，我们从两个不同的线程中访问数据，它们中至少有一个改变了数据但是没有正确地同步。如果你对数据竞争不熟悉，我强烈建议搜索一下相关主题，因为这对于几乎当今所有的开发者都是很重要的。回到COW，背后的思想并不复杂。就是尽可能地往后推迟数据的拷贝。与其在我们把一片数据赋值给多个变量时进行拷贝，倒不如在通过变量进行写入的时候进行拷贝。</p>
<h2 id="copy-on-write-in-c"><a class="header" href="#copy-on-write-in-c">Copy-On-Write in C++</a></h2>
<p>尽管核心思想很简单，但是Rust和C++在实现这种优化上采取了不同的方案。让我们先从C++这边开始，不过我要提醒你这是一个粗略的简介，只是讲一些需要用到的东西，即使你从来没学过C++。在C++里，我们通常在一个类里放入大量的数据，这些数据会有赋值操作。每一次我们把一个变量赋值给另一个变量，我们就会调用这个赋值操作，默认情况下是拷贝整条数据。但是，这个行为是可以修改的，所以通常情况下，COW就是利用这一点来实现的。C++中的COW不是一个单独的抽象，而是每个类进行单独实现。传统的做法是通过修改赋值操作符返回一个指向同一个底层数据的指针。尽管这还不够，但是现在我们已经可以让多个变量指向同一份数据。所以每次我们想修改数据的时候，我们都可能遇到之前提到的数据竞争。我们可以在每次进行修改操作的时候都拷贝数据，但是这样会很浪费。如果我们的变量是唯一指向数据的，我们就没理由拷贝信息。只有我们有多个变量引用到这份数据，我们才需要去拷贝。这意味着我们不得不去跟踪另一个重要的信息，即有多少变量引用同一份数据。我们在赋值操作时增加共享计数，在变量离开作用域时减少计数。新的数据拷贝会有新的计数，其初始化值为一。记住这个计数，这会是本文的一个关键元素。</p>
<h2 id="copy-on-write-in-rust"><a class="header" href="#copy-on-write-in-rust">Copy-On-Write in Rust</a></h2>
<p>和C++不一样，Rust更注重安全，强类型，和显式抽象。因此，COW在Rust中拥有自己的类型便不足为奇，我们可以把这个类型用于已经存在的数据。在Rust中，COW是拥有两个状态的枚举(enums)，这两个状态是<code>Owned</code>和<code>Borrowed</code>。对于non-rustacean，你可能想要阅读我另一篇关于 <a href="https://link.zhihu.com/?target=http%3A//oribenshir.github.io/afternoon_rusting//blog/enum-and-pattern-matching-part-1">Enum &amp; Pattern Matching - Part 1</a>的文章。<code>Owned</code>包含了一个被拥有类型的值。<code>Borrowed</code>拥有一个对类型的引用的关联类型。这使得Rust的所有权系统能够开始运转。这意味着每一份数据最多只能拥有一个<code>Owned</code>类型的COW变量但是可以有很多<code>Borrowed</code>变量。通过COW，我们可以调用其所依赖的类上的任何不会修改数据的方法。如果我们确实想要修改数据，我们不得不调用COW上的一个名为<code>to_mut</code>的函数。当我们调用<code>to_mut</code>的时候，一个很直观的操作发生了。如果我们在<code>Borrowed</code>状态，这个数据会被克隆，而在<code>Owned</code>状态，我们只是获取这个数据，相当于空操作(no-op)。所以和C++不同，不是所有对数据的引用都生而平等。我们决定什么时候写代码，我们的COW将会有什么类型的状态，哪些因素决定这个数据是否会被克隆。在Rust里，COW是在数据之上一层很方便的包装，允许我们不知道它的所有权，并且因此可以节省不必要的数据克隆。当然，在Rust中使用COW也会有相应的开销。当我们创建一个<code>Borrowed</code>COW时，Rust所有权系统开始生效。这意味着编译器需要能够证明这个数据活的足够长，这就强制要求只要COW还存在，我们就得持有(hold on)原始的变量，这些我们在C++里是不需要的。所有的这些变化导致了不同的抽象方式。和C++不同，在Rust里，它不是完全不可见的，我们需要做一些工作。我们需要把数据包装(wrap)进一个COW并且回到原始类型的时候需要解包(unwrap)。还有，每当我们想要修改数据的时候，我们不得不调用<code>to_mut</code>。</p>
<h2 id="is-copy-on-write-a-pessimization"><a class="header" href="#is-copy-on-write-a-pessimization">Is Copy-On-Write a pessimization?</a></h2>
<p>回到Herb Suctter写的那篇文章。尽管我们已经知道COW拥有坚实而有逻辑的基础，但是他很详细地阐述了，在很多情况下，COWs实际上是最差的(方案)。Herb是C++圈子里比较有影响力的人之一，所以难怪在最后，C++11里，禁止了C++的string实现。非常感谢这篇文章，后来，我会详细介绍为什么他提出了这种观点。但是首先，我们应该理解这种观点适用于什么情况。Herb的文章里阐述了必要的前提条件：</p>
<ol>
<li>这个库可能构建于多线程使用，这意味着即使你的程序是单线程的，也可能会受到退化(degradation)的影响</li>
<li>例子是用C++写的，但是这个讨论适用于任何语言。</li>
</ol>
<p>这些前置条件很重要因为它们同样适用于Rust的用例。Rust的COW实现了<code>Send</code>和<code>Sync</code>特性(traits)，这是由于Rust的安全性要求，意味着这种实现是设计用于多线程程序中。当然，Herb认为他的观点在任何语言中都是有效的，不只是C++。 最基本的，如果Herb是对的，我们应该预期当使用Rust的COW时，能看到性能上的退化，即使是在单线程程序中。这篇文章的剩余部分就是在解决这些关于COW效率的看上去又相互矛盾的观点。我也会阐述双方都有有力的证据证明各自的观点。最重要的是，我们会找到一个中间位置并解释每个人都是对的。最后，我会解释，为什么是Rust在这些语言的对比中占了上风。</p>
<h2 id="benchmarking-copy-on-write-in-rust"><a class="header" href="#benchmarking-copy-on-write-in-rust">Benchmarking Copy-On-Write in Rust</a></h2>
<p>我们可以从简单的开始，来证明优化就是优化，我们要做的就是使用一些用例的基准测试来证明它。让我们用一个简单的用例来测试Rust的COW。即使是单线程的用例也可以。正如我们在第一个表述中说到的，即使是在单线程情况下，支持多线程用例的COW也会导致退化。我们的用例是简单的，作为开发者我们总会遇到这样的任务。我们有很多客户端，产生类似的数据，但是有不同的格式，我们必须把它们统一成相同的格式。我们的任务要获取URL，其中一些是(&quot;https//&quot;)协议为前缀，但是其他的不是。如果URL缺少这个前缀，我们就给它加上。这里是对这个任务的5个不同的实现，以各种方式来接收输入和重新得到输出。</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub fn add_http_prefix_1(input: &amp;str) -&gt; String {
    if input.starts_with(&quot;https://&quot;) {
        String::from(input)
    } else {
        [&quot;https://&quot;, input].concat()
    }
}

pub fn add_http_prefix_2(mut input: String) -&gt; String {
    if input.starts_with(&quot;https://&quot;) {
        input
    } else {
        input.insert_str(0, &quot;https://&quot;);
        input
    }
}

pub fn add_http_prefix_3&lt;T: AsRef&lt;str&gt;&gt;(input: T) -&gt; String {
    if input.as_ref().starts_with(&quot;https://&quot;) {
        String::from(input.as_ref())
    } else {
        [&quot;https://&quot;, input.as_ref()].concat()
    }
}


pub fn add_http_prefix_4(input: &amp;str) -&gt; Cow&lt;str&gt; {
    if input.starts_with(&quot;https://&quot;) {
        Cow::Borrowed(input)
    } else {
        Cow::Owned([&quot;https://&quot;, input].concat())
    }
}

pub fn add_http_prefix_5(input: Cow&lt;str&gt;) -&gt; Cow&lt;str&gt; {
    if input.as_ref().starts_with(&quot;https://&quot;) {
        input
    } else {
        match input {
            Cow::Owned(mut input) =&gt; {
                input.insert_str(0, &quot;https://&quot;);
                Cow::Owned(input)
            }
            Cow::Borrowed(input) =&gt; {
                Cow::Owned([&quot;https://&quot;, input.as_ref()].concat())
            }
        }
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>前面三种是比较常见的做法，每一个都做相同的任务，第一个只是借用了输入，第二个拥有完整的所有权，第三个使用了模板，这样能让用户选择是把这个值借我们还是给我们。在所有的情况下，我们不得不返回一个新的被拥有的字符串，因为我们可能会修改输入的内容。第四个实现借用数据，但是没有创建有一个新的字符串，而是充分利用在某些时候下我们不会修改输入内容这一情况。它让我们在没有修改的情况下重新取回COW的借用变量，当有修改发生的情况下，返回被拥有(owned)的版本。第五个实现更进一步地将输入也改成了COW。</p>
<p>这是我第一次用Rust代码进行测试，我选择使用<code>criterion</code>因为它似乎是这类任务的首选。测试在我的家用PC，一台Intel i7 8700，16G内存，运行Windows10的机器上进行。我尝试在性能测试期间尽可能地关闭后台干扰程序。这是我的最基本的测试代码:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub fn criterion_benchmark(c: &amp;mut Criterion) {
    c.bench_function(&quot;test1&quot;, |b| b.iter(|| cow_perf::add_http_prefix_1(black_box(&quot;test&quot;))));
    c.bench_function(&quot;test2&quot;, |b| b.iter(|| cow_perf::add_http_prefix_2(black_box(String::from(&quot;test&quot;)))));
    c.bench_function(&quot;test3&quot;, |b| b.iter(|| cow_perf::add_http_prefix_3(black_box(&quot;test&quot;))));
    c.bench_function(&quot;test4&quot;, |b| b.iter(|| cow_perf::add_http_prefix_4(black_box(&quot;test&quot;))));
    c.bench_function(&quot;test5&quot;, |b| b.iter(|| cow_perf::add_http_prefix_5(black_box(Cow::Borrowed(&quot;test&quot;)))));

    c.bench_function(&quot;test1_2&quot;, |b| b.iter(|| cow_perf::add_http_prefix_1(black_box(&quot;https://test&quot;))));
    c.bench_function(&quot;test2_2&quot;, |b| b.iter(|| cow_perf::add_http_prefix_2(black_box(String::from(&quot;https://test&quot;)))));
    c.bench_function(&quot;test3_2&quot;, |b| b.iter(|| cow_perf::add_http_prefix_3(black_box(&quot;https://test&quot;))));
    c.bench_function(&quot;test4_2&quot;, |b| b.iter(|| cow_perf::add_http_prefix_4(black_box(&quot;https://test&quot;))));
    c.bench_function(&quot;test5_2&quot;, |b| b.iter(|| cow_perf::add_http_prefix_5(black_box(Cow::Borrowed(&quot;https://test&quot;)))));
}

fn custom_criterion() -&gt; Criterion {
    Criterion::default()
        .sample_size(1000)
}

criterion_group!(
    name = benches;
    config = custom_criterion();
    targets = criterion_benchmark);

criterion_main!(benches);
<span class="boring">}
</span></code></pre></pre>
<p>我们不在此处浪费时间去测试，简单地来看一下测试的结果：</p>
<p><img src="pict%5C001.webp" alt="" /></p>
<p><img src="pict%5C002.webp" alt="" /></p>
<p>本文的主要内容就是要深入讨论这个测试结果。你们中的一些人可能甚至注意到我没有提供原始数据。其实我确实提供了重现结果需要的所有信息。而且，在深入数字之前，请记住基准测试(benchmark)是一个复杂的主题，比人们通常认为的要复杂的多。结果表明，并没有必要很精确地计较每种实现带来地好处/损失。这些对于我们理解整体的趋势已经是足够了，尤其是与我们的预期相一致时。我们将会把结果精简到我们只关心的那部分，来看看COW是否有助于提升性能。我会只集中讨论第一种和第四种实现。第一种实现，虽然在非COW实现中平均成绩不是表现最好的，但是当需要修改数据时却是性能最好的。第四个实现是使用COW优化的实现中表现最好的。结果显而易见。当我们需要修改数据时，COW比较慢。在这次测试中，第四个实现比第一个实现慢了13%(但是情况不一定每次都一样)。另一方面，当我们不需要修改数据时，第四个实现比第一个实现高出96%。</p>
<p>最主要的，在Rust中使用COW时，当我们想要做的只是读数据时，只要每次需要修改数据时增加一点儿成本就能获得巨大的收益。有很多用例都可以利用这一点来提高性能。这显然不像是Herb在讨论中提到的最差化(pessimization)。</p>
<h2 id="understanding-why-copy-on-write-might-be-a-pessimization"><a class="header" href="#understanding-why-copy-on-write-might-be-a-pessimization">Understanding why Copy-On-Write might be a pessimization</a></h2>
<p>验证Herb的观点还是比较困难的。我们可以进行一次性能测试，在测试中COW在C++中的应用确实降低了性能。Herb也在他的文章中提到了一些。但是这些还不够，因为有人能够合理地认为问题是出在实现上，或者会提供给我们一个用例以及相关测试。Herb的观点比这更深刻，它们到达了这个优化的核心。他表明这个优化核心里的某些东西导致了在多线程情况下的性能衰退。我们没有办法绕过它，只能好好地去理解。</p>
<p>在Herb的核心观点中，有一些比拷贝数据代价更为昂贵的操作，在我们的用例中，我们讨论的是数据同步。当我们不得不对并发访问的数据进行同步时，这比单纯地拷贝数据需要更多的时间。现在，正如在C++所做的那样，如果我们想要保持COW对用户不可见，所有对COW共享数据的引用必须有相同的行为，是否只有一个这样的变量。和Rust不同，我们不能要求谁应该活的更久，或者给这些引用以各种方式打上标签，因为我们不在没有使用COW优化的引用上这么做。正如我们之前看到的，它会给我们造成一种没有任何额外数据的情况，这样子我就不能确定是否应该去拷贝共享数据。在更早一点儿的时候，我们使用一个引用计数来进行决定。很显然引用计数是需要被同步的，因为它会被并发访问。每一个访问都有可能修改计数的值。Herb认为，同步成本高于由减少数据拷贝带来的性能提升。</p>
<h2 id="rusts-smart-design-choice"><a class="header" href="#rusts-smart-design-choice">Rust’s smart design choice</a></h2>
<p>现在我们已经看到，在Rust的情况中，我们可以使用一个比较聪明的设计来避免同步的成本。但是我们也要付出相应的代价，COW在Rust中是不可见的，我们不得不明确对COW的使用。让我们来看一下Rust是如何避免额外的同步成本的。和几乎是全部用C++实现的COW标准模块不同，Rust采取了另一种方法。正如我们之前所看到的，Rust中的COW只是让我们无法知晓数据的所有权。理解这个地方最本质的一点在于我们在编译期知道所有权。事实上，它是在运行时由输入决定的，但是对于任意的给定值，结果是确定的，我们要么拥有这个数据要么借用它。在我们的例子中，如果数据有&quot;https://&quot;的前缀，我们就只需要借用。否则，我们就拥有数据的所有权。我们只根据在编译期获知的所有权信息来决定是否拷贝数据。因此，我们不需要在对数据不同的引用之间保存额外的信息。因此，Rust中的COW不需要承担同步额外信息所带来的额外开销从而即便在多线程环境下也能实现真正的优化。</p>
<p>所以，我们看到在构建COW抽象的时候一个小小的修改是如何让我们在多线程环境下依然能够保持带来的好处。为此需要承担的代价在很多情况下都是可以忽略不计的，尽管它确实存在。COW的好处有时候也会消失，因为我们可能不得不让原始的数据保存地比它实际需要的时间更久。而且，数据的修改同样十分昂贵。</p>
<h2 id="why-c-lost-to-rust-in-this-front"><a class="header" href="#why-c-lost-to-rust-in-this-front">Why C++ lost to Rust in this front</a></h2>
<p>现在我们剩下最后一个问题了。Rust的设计者尝试提出一种很好的设计来克服Herb在COW中发现的缺点。这似乎只要我们在需要使用COW的时候只需要付出一丁点的开销。但是这个设计只适用于Rust，或者说是以Herb为代表的这类人的疏忽，C++是否能够进行这种抽象？答案比我想的要复杂一些。事实上，C++什么都可以做到，所以我们可以尝试在C++中创建类似的COW。但是C++缺少像Rust的生命周期这样的关键特性使其有可能行得通。我们没有办法在C++中满足保留原始数据的要求。毫无疑问，我们可以告诉用户它们要把原始变量保存地足够长。它和之前听过的C++里不安全的东西还不太一样。尽管，当COW作为成员嵌入到另一个类时，那个类的用户甚至没有意识到COW的存在。要跟踪所需要的数据是否能活那么久几乎是不可能的。并且在C++标准中，这种不安全性也是不会被采纳的。这就告诉我们Rust的安全性确实帮助我们获得了比C++更好的性能。因为一些抽象真的是太不安全了，即使是对C++来讲。</p>
<p>Herb指出COW中存在的缺陷这件事是正确的。为了让优化依然有效，Rust在优化能力和易用性上做了一些妥协。Rust中的COWs更加复杂，也有更多的要求（保持原有数据存在足够长的时间）。不是C++中所有可能的COWs都能在Rust中实现。最明显地，在库内部的事物之后添加COW是不可能的，因为用户必须意识到它。但是Rust的设计者依然是对的，Rust中的COW如果使用合理地话，能够为优化提供很好的可能。我发现这对于C++和Rust拥护者无休止的争议来讲，是一个令人高兴的中间地带，因为有一种语言明显在这个话题上胜出了。Rust为安全性而设计，设计良好的生命周期使得Rust创造出了在C++中一直梦寐以求的更好的抽象。并且在这个特殊的案例中，我们也能看到，这个概念是如何实实在在地改善了性能。这是Rust压倒性的胜利。</p>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                            <a rel="prev" href="../../empty.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>

                            <a rel="next" href="../../08_奇技淫巧/揭秘神奇的Rust_Axum风格的函数实现/揭秘神奇的Rust_Axum风格的函数实现.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                    <a rel="prev" href="../../empty.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>

                    <a rel="next" href="../../08_奇技淫巧/揭秘神奇的Rust_Axum风格的函数实现/揭秘神奇的Rust_Axum风格的函数实现.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
            </nav>

        </div>




        <script type="text/javascript">
            window.playground_copyable = true;
        </script>


        <script src="../../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../searcher.js" type="text/javascript" charset="utf-8"></script>

        <script src="../../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->


    </body>
</html>
